/*--------------------------------------------------------------
 * File: data.c 编码类型：C语言  UTF-8
 * Author WRS (1352509846@qq.com)
 * 功能: 数据生成功能
 * Version 0.1
 * Date 2024-04-26 
 * 
 * @copyright Copyright (c) 2024
 * 
----------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include "esp_timer.h"  // 包含获取系统时钟 tick 的函数声明
#include "esp_mac.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "data.h"
#include "myDebug.h"
#include "cJSON.h"
#include "global.h"
#include "TypeDefine.h"
#include "devBML04.h"

static const char *TAG = "Data ";

void json_test(void)
{
    cJSON *device_upload_cjson = NULL;
    char *access_data = NULL;   //接入数据
    // char *upload_data = NULL;   //上传数据
    device_upload_cjson = cJSON_CreateObject();
    if (device_upload_cjson == NULL)
    {
        printf("Error before: [%s]\n", cJSON_GetErrorPtr());
        return ;
    }
    cJSON_AddNumberToObject(device_upload_cjson, "ver",  1);    
    cJSON_AddNumberToObject(device_upload_cjson, "type", 1);   
    cJSON_AddNumberToObject(device_upload_cjson, "func", 101); 
    access_data = cJSON_Print(device_upload_cjson);
    printf("access_data: %s\n", access_data);
    cJSON_Delete(device_upload_cjson);
    free(access_data);
}

/*--------------------------------------------------------------
 * 功能: 随机数种子初始化
 * 
----------------------------------------------------------------*/
void Random_Seed_Init(void)
{
    uint8_t mac[8];
    // 使用ESP32的唯一标识符ID和系统时钟 tick 作为随机数种子
    esp_efuse_mac_get_default(mac);
    uint64_t chip_id = *((uint64_t*)mac);
    uint64_t sys_tick = esp_timer_get_time();

    ESP_LOGI(TAG, "Chip ID: %llX, System Tick: %llX", chip_id, sys_tick);
    srand((unsigned int)(chip_id ^ sys_tick));
}


/*--------------------------------------------------------------
 * 功能: 生成一个在指定范围内的随机整数
 * 包括两个边界值
 * 参数: min 最小值
 * 参数: max 最大值
 * 返回值: int 
----------------------------------------------------------------*/
int Random_data_in_range(int min, int max)
{
    return min + rand() % (max - min + 1);
}

/*--------------------------------------------------------------
 * 功能: 生成一个在指定范围内的线性变化整数
 * 包括两个边界值
 * 参数: min 最小值
 * 参数: max 最大值
 * 返回值: int 
----------------------------------------------------------------*/
int Linear_data_in_range(int min, int max, int incdata)
{
    static int current_value = 0;     // 当前值，初始为 min
    static int incrementing = 1;         // 控制递增 (1) 或递减 (-1)

    // 根据方向进行递增或递减
    if (incrementing == 1) {
        current_value += incdata;  // 递增
        if (current_value >= max) {
            current_value = max;  // 达到上限
            incrementing = -1;    // 切换为递减
        }
    } else {
        current_value -= incdata;  // 递减
        if (current_value <= min) {
            current_value = min;  // 达到下限
            incrementing = 1;     // 切换为递增
        }
    }

    return current_value;  // 返回当前值
}


/*--------------------------------------------------------------
 * 功能: 生成正弦波形变化的随机数据
 * 
 * 参数: amplitude 振幅
 * 参数: frequency 频率（Hz）
 * 参数: phase_shift 相位偏移
 * 返回值: double 生成的正弦变化的随机数据
----------------------------------------------------------------*/
double Random_data_in_sin(double amplitude, double frequency, double phase_shift)
{
    double time = (double)esp_timer_get_time() / 1000000.0; // 将微秒转换为秒
    return amplitude * sin(2 * M_PI * frequency * time + phase_shift);
}


/*--------------------------------------------------------------
 * 功能: 生成余弦波形变化的随机数据
 * 
 * 参数: amplitude 振幅
 * 参数: frequency 频率（Hz）
 * 参数: phase_shift 相位偏移
 * 返回值: double 生成的余弦变化的随机数据
----------------------------------------------------------------*/
double Random_data_in_cos(double amplitude, double frequency, double phase_shift)
{
    double time = (double)esp_timer_get_time() / 1000000.0; // 将微秒转换为秒
    return amplitude * cos(2 * M_PI * frequency * time + phase_shift);
}

/*--------------------------------------------------------------
 * 功能: 固定数值的数据
 * 
 * 参数: value 
 * 返回值: int 
----------------------------------------------------------------*/
int Random_data_fixed(int value)
{
    return value;
}

/*--------------------------------------------------------------
 * 功能: 使用外部输入的数据（SD卡）
 * 
 * 参数: type 
 * 返回值: int 
----------------------------------------------------------------*/
int Random_data_outside(uint8_t type)
{
    switch (type)
    {
        case 1: // SD卡中的数据
            {return 1;}
            break;

        case 2: // 手动输入的数据
            {return 2;}
            break;        
        default:
            break;
    }
    return 0;
}


void NVS_data_init(void)
{
    // Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) 
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK( ret );
}

/*--------------------------------------------------------------
 * 功能: 从nvs中读取字符值
 * 
 * 参数: namespace NVS命名空间
 * 参数: key 要读取的键值
 * 参数: value 读到的值
 * 参数: maxlen 外部存储数组的最大值
 * 返回值: size_t 读取到的字节数
----------------------------------------------------------------*/
size_t NVS_data_read_str(const char* namespace, const char* key, char* value, int maxlen)
{
    nvs_handle_t nvs_handle;
    esp_err_t ret_val = ESP_FAIL;
    size_t required_size = 0;
    ESP_ERROR_CHECK(nvs_open(namespace, NVS_READWRITE, &nvs_handle));
    ret_val = nvs_get_str(nvs_handle, key, NULL, &required_size);
    if(ret_val == ESP_OK && required_size <= maxlen)
    {
        nvs_get_str(nvs_handle,key,value,&required_size);
    }
    else
        required_size = 0;
    nvs_close(nvs_handle);
    return required_size;
}

/*--------------------------------------------------------------
 * 功能: 写入值到NVS中（字符数据）
 * 
 * 参数: namespace NVS命名空间
 * 参数: key NVS键值
 * 参数: value 需要写入的值
 * 返回值: esp_err_t 
----------------------------------------------------------------*/
esp_err_t NVS_data_write_str(const char* namespace,const char* key,const char* value)
{
    nvs_handle_t nvs_handle;
    esp_err_t ret;
    ESP_ERROR_CHECK(nvs_open(namespace, NVS_READWRITE, &nvs_handle));
    
    ret = nvs_set_str(nvs_handle, key, value);
    nvs_commit(nvs_handle);
    nvs_close(nvs_handle);
    return ret;
}

/*--------------------------------------------------------------
 * 功能: 从nvs中读取字节数据（二进制）
 * 
 * 参数: namespace NVS命名空间
 * 参数: key 要读取的键值
 * 参数: value 读到的值
 * 参数: maxlen 外部存储数组的最大值
 * 返回值: size_t 
----------------------------------------------------------------*/
size_t NVS_data_read_blob(const char* namespace, const char* key, uint8_t *value, int maxlen)
{
    nvs_handle_t nvs_handle;
    esp_err_t ret_val = ESP_FAIL;
    size_t required_size = 0;
    ESP_ERROR_CHECK(nvs_open(namespace, NVS_READWRITE, &nvs_handle));
    ret_val = nvs_get_blob(nvs_handle, key, NULL, &required_size);
    if(ret_val == ESP_OK && required_size <= maxlen)
    {
        nvs_get_blob(nvs_handle,key,value,&required_size);
    }
    else
        required_size = 0;
    nvs_close(nvs_handle);
    return required_size;
}

/*--------------------------------------------------------------
 * 功能: 写入值到NVS中(字节数据)
 * 
 * 参数: namespace NVS命名空间
 * 参数: key NVS键值
 * 参数: value 需要写入的值
 * 参数: len 要写入的长度
 * 返回值: esp_err_t 
----------------------------------------------------------------*/
esp_err_t NVS_data_write_blob(const char* namespace, const char* key, uint8_t* value, size_t len)
{
    nvs_handle_t nvs_handle;
    esp_err_t ret;
    ESP_ERROR_CHECK(nvs_open(namespace, NVS_READWRITE, &nvs_handle));
    ret = nvs_set_blob(nvs_handle, key, value,len);
    nvs_commit(nvs_handle);
    nvs_close(nvs_handle);
    return ret;
}

/*--------------------------------------------------------------
 * 功能: 擦除nvs区中某个键
 * 
 * 参数: namespace NVS命名空间
 * 参数: key 要操作的键值
 * 返回值: esp_err_t 
----------------------------------------------------------------*/
esp_err_t NVS_data_erase_key(const char* namespace,const char* key)
{
    nvs_handle_t nvs_handle;
    esp_err_t ret_val = ESP_FAIL;
    ESP_ERROR_CHECK(nvs_open(namespace, NVS_READWRITE, &nvs_handle));
    ret_val = nvs_erase_key(nvs_handle,key);
    ret_val = nvs_commit(nvs_handle);
    nvs_close(nvs_handle);
    return ret_val;
}

void parse_bml04_json(cJSON *device)
{
    if (!device)
        return;

    // 解析通用字段
    cJSON *num = cJSON_GetObjectItem(device, "num");  
    if(cJSON_IsNumber(num))
    {
        if(num->valueint == 0 || num->valueint > BML04_MAX_NUM)
        {
            MY_JSON("bml04 num = %d", num->valueint);
            bml04_info.dev_num = 0;  
            return ;
        }
        bml04_info.dev_num = num->valueint;
        // 清空地址
        RestoreFactory(Env_st.MasterPort, bml04_info.devType);
        // 自动申请地址
        AutoRequestAddresses(Env_st.MasterPort, bml04_info.devType, bml04_info.dev_num);
    }
    
    // 解析实例数组
    cJSON *instances = cJSON_GetObjectItem(device, "instances");
    if (!cJSON_IsArray(instances))
        return;
    MY_JSON("bml04 num = %d", bml04_info.dev_num);
    int instance_index = 0;
    cJSON *instance;
    cJSON_ArrayForEach(instance, instances)
    {
        if (instance_index > BML04_MAX_NUM)
            break;

        cJSON *id = cJSON_GetObjectItem(instance, "id");
        if (cJSON_IsString(id))
        {
            MY_JSON("id = %s", id->valuestring);
        }

        cJSON *ai_mode = cJSON_GetObjectItem(instance, "ai_mode");
        if (cJSON_IsArray(ai_mode))
        {
            int ai_mode_count = cJSON_GetArraySize(ai_mode); // 获取数组长度
            for (int i = 0; i < BML04_AIChannel; i++)
            {
                if(i < ai_mode_count)
                {
                    cJSON *item = cJSON_GetArrayItem(ai_mode, i);
                    bml04_info.dev_AI_SDmode[instance_index][i] = cJSON_IsNumber(item) ? item->valueint : 0;
                }
                else
                {
                    bml04_info.dev_AI_SDmode[instance_index][i] = 0;
                }                
            }
        }

        cJSON *ai_data_file = cJSON_GetObjectItem(instance, "ai_data_file");
        if (cJSON_IsString(ai_data_file))
        {
            strncpy(bml04_info.dev_AI_dataFileName[instance_index], ai_data_file->valuestring, sizeof(bml04_info.dev_AI_dataFileName[instance_index]));
        }

        cJSON *ai1_range = cJSON_GetObjectItem(instance, "ai1_range");
        if (cJSON_IsArray(ai1_range) && cJSON_GetArraySize(ai1_range) == 3)
        {
            for(int i = 0; i < 3; i++)
            {
                cJSON *item = cJSON_GetArrayItem(ai1_range, i);
                bml04_info.dev_AI_SDrange[instance_index][0][i] = cJSON_IsNumber(item) ? (float)item->valuedouble : 0.0f;
            }
        }
        cJSON *ai2_range = cJSON_GetObjectItem(instance, "ai2_range");
        if (cJSON_IsArray(ai2_range) && cJSON_GetArraySize(ai2_range) == 3)
        {
            for(int i = 0; i < 3; i++)
            {
                cJSON *item = cJSON_GetArrayItem(ai2_range, i);
                bml04_info.dev_AI_SDrange[instance_index][1][i] = cJSON_IsNumber(item) ? (float)item->valuedouble : 0.0f;
            }
        }
        cJSON *ai3_range = cJSON_GetObjectItem(instance, "ai3_range");
        if (cJSON_IsArray(ai3_range) && cJSON_GetArraySize(ai3_range) == 3)
        {
            for(int i = 0; i < 3; i++)
            {
                cJSON *item = cJSON_GetArrayItem(ai3_range, i);
                bml04_info.dev_AI_SDrange[instance_index][2][i] = cJSON_IsNumber(item) ? (float)item->valuedouble : 0.0f;
            }
        }
        cJSON *ai4_range = cJSON_GetObjectItem(instance, "ai4_range");
        if (cJSON_IsArray(ai4_range) && cJSON_GetArraySize(ai4_range) == 3)
        {
            for(int i = 0; i < 3; i++)
            {
                cJSON *item = cJSON_GetArrayItem(ai4_range, i);
                bml04_info.dev_AI_SDrange[instance_index][3][i] = cJSON_IsNumber(item) ? (float)item->valuedouble : 0.0f;
            }
        }

        instance_index++;
    }
    //-----------------------------------------------------------------------------------------
    // 打印 dev_AI_SDmode 数组
    // printf("dev_AI_SDmode:\n");
    // for (int i = 0; i < BML04_MAX_NUM; i++)
    // {
    //     for (int j = 0; j < BML04_AIChannel; j++)
    //     {
    //         printf("bml04_info.dev_AI_SDmode[%d][%d] = %d\n", i, j, bml04_info.dev_AI_SDmode[i][j]);
    //     }
    // }

    // // 打印 dev_AI_SDrange 数组
    // printf("\ndev_AI_SDrange:\n");
    // for (int i = 0; i < BML04_MAX_NUM; i++)
    // {
    //     for (int j = 0; j < BML04_AIChannel; j++)
    //     {
    //         printf("bml04_info.dev_AI_SDrange[%d][%d] = [%f, %f, %f]\n",
    //                i, j,
    //                bml04_info.dev_AI_SDrange[i][j][0],
    //                bml04_info.dev_AI_SDrange[i][j][1],
    //                bml04_info.dev_AI_SDrange[i][j][2]);
    //     }
    // }

    // // 打印 dev_AI_dataFileName 数组
    // printf("\ndev_AI_dataFileName:\n");
    // for (int i = 0; i < BML04_MAX_NUM; i++)
    // {
    //     printf("bml04_info.dev_AI_dataFileName[%d] = %s\n", i, bml04_info.dev_AI_dataFileName[i]);
    // }
}

/*--------------------------------------------------------------
 * 功能: 解析配置文件中的内容
 * 
 * 参数: text 
----------------------------------------------------------------*/
static void parseJsonText(char *text)
{
    cJSON *json = NULL;
    cJSON *dev;
    int device_index = 0;
    
    if(text == NULL)
    {
        MY_ERROR("text is NULL\n");
        return ;
    }    

    json = cJSON_Parse(text);
    if (json == NULL)
    {
        MY_ERROR("Error before: [%s]\n", cJSON_GetErrorPtr());
        return ;
    }
    
    cJSON *devices = cJSON_GetObjectItem(json, "devices");
    if (!cJSON_IsArray(devices)) {
        printf("Devices is not an array\n");
        cJSON_Delete(json);
        return;
    }

    cJSON_ArrayForEach(dev, devices)
    {
        if (device_index >= BML04_MAX_NUM)
            break;

        // 获取设备类型
        cJSON *type = cJSON_GetObjectItem(dev, "type");
        if (cJSON_IsString(type) && strcmp(type->valuestring, "BML04") == 0)
        {
            parse_bml04_json(dev);
        }
        else
        {
            continue;
        }
    }

    cJSON_Delete(json);
}

void SD_Conf_init(char *sd_conf_file)
{
    FILE *fp = NULL;
    long len;
    char *data;

    // 只读的打开配置文件
    fp = fopen(sd_conf_file, "r");
    if(fp == NULL)
    {
        MY_ERROR("%s file open ERROR\n", sd_conf_file);
        return ;
    }

    // 求出文件中的内容长度
    fseek(fp, 0, SEEK_END);
    len = ftell(fp); 

    // 指针偏移到文件头
    fseek(fp, 0, SEEK_SET);

    // 读取文件中的内容
    data = (char *)malloc(len + 1);
    if(data == NULL)
    {
        MY_ERROR("malloc ERROR\n");
        fclose(fp);
        return ;
    }
    fread(data, 1, len, fp);
    fclose(fp);
    data[len] = '\0';

    // 解析配置文件数据
    parseJsonText(data);
    free(data);
}

